package bean.managed;

import entity.BillingRequestEntity;
import bean.managed.util.JsfUtil;
import bean.session.BillingRequestEntityFacade;

import entity.CustomerInvoiceEntity;
import entity.SalesOrderEntity;
import exception.CustomerAccountDoesNotExistException;
import java.io.Serializable;
import java.util.Calendar;
import java.util.List;
import java.util.ResourceBundle;
import javax.ejb.EJB;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.SessionScoped;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.FacesConverter;
import javax.faces.model.SelectItem;
import javax.servlet.http.HttpServletRequest;
import managedbean.AbstractBacking;
import managedbean.DownloadPDF;
import type.InvoiceStatus;
import type.InvoiceType;
import util.PDFGenerator;

@ManagedBean(name = "billingRequestEntityController")
@SessionScoped
public class BillingRequestEntityController extends AbstractBacking implements Serializable {

    private List<BillingRequestEntity> allCIABillingRequests;
    private List<BillingRequestEntity> allNormalBillingRequests;
    private List<BillingRequestEntity> allBillingRequestsForSalesOrder;
    private BillingRequestEntity current;
    @EJB
    private bean.session.BillingRequestEntityFacade ejbFacade;
    @EJB
    private bean.session.CustomerInvoiceEntityFacade customerInvoiceFacade;
    @EJB
    private bean.session.SalesOrderEntityFacade salesOrderFacade;
    @ManagedProperty(value = "#{customerInvoiceEntityController}")
    private CustomerInvoiceEntityController customerInvoiceEntityController;
    @ManagedProperty(value = "#{downloadPdf}")
    private DownloadPDF pdfDownloadController;
    @ManagedProperty(value = "#{salesOrderEntityController}")
    private SalesOrderEntityController salesOrderEntityController;

    public BillingRequestEntityController() {
    }

    public BillingRequestEntity getSelected() {
        if (current == null) {
            current = new BillingRequestEntity();
        }
        return current;
    }

    private BillingRequestEntityFacade getFacade() {
        return ejbFacade;
    }

    public String prepareList() {
        recreateModel();
        return "List";
    }

    public String prepareView() {
        return "View";
    }

    public String prepareCreate() {
        return "Create";
    }

    public String create() {
        try {
            getFacade().create(current);
            JsfUtil.addSuccessMessage(ResourceBundle.getBundle("/Bundle").getString("BillingRequestEntityCreated"));
            return prepareCreate();
        } catch (Exception e) {
            JsfUtil.addErrorMessage(e, ResourceBundle.getBundle("/Bundle").getString("PersistenceErrorOccured"));
            return null;
        }
    }

    public String prepareEdit() {
        return "Edit";
    }

    public String update() {
        try {
            getFacade().edit(current);
            JsfUtil.addSuccessMessage(ResourceBundle.getBundle("/Bundle").getString("BillingRequestEntityUpdated"));
            return "View";
        } catch (Exception e) {
            JsfUtil.addErrorMessage(e, ResourceBundle.getBundle("/Bundle").getString("PersistenceErrorOccured"));
            return null;
        }
    }

    public String destroy() {
        performDestroy();
        recreateModel();
        return "List";
    }

    public String destroyAndView() {
        performDestroy();
        recreateModel();
        // all items were removed - go back to list
        return "List";
    }

    private void performDestroy() {
        try {
            getFacade().remove(current);
            JsfUtil.addSuccessMessage(ResourceBundle.getBundle("/Bundle").getString("BillingRequestEntityDeleted"));
        } catch (Exception e) {
            JsfUtil.addErrorMessage(e, ResourceBundle.getBundle("/Bundle").getString("PersistenceErrorOccured"));
        }
    }

    private void recreateModel() {
        current = null;
    }

    public SelectItem[] getItemsAvailableSelectMany() {
        return JsfUtil.getSelectItems(ejbFacade.findAll(), false);
    }

    public SelectItem[] getItemsAvailableSelectOne() {
        return JsfUtil.getSelectItems(ejbFacade.findAll(), true);
    }

    @FacesConverter(forClass = BillingRequestEntity.class)
    public static class BillingRequestEntityControllerConverter implements Converter {

        public Object getAsObject(FacesContext facesContext, UIComponent component, String value) {
            if (value == null || value.length() == 0) {
                return null;
            }
            BillingRequestEntityController controller = (BillingRequestEntityController) facesContext.getApplication().getELResolver().
                    getValue(facesContext.getELContext(), null, "billingRequestEntityController");
            return controller.ejbFacade.find(getKey(value));
        }

        java.lang.Long getKey(String value) {
            java.lang.Long key;
            key = Long.valueOf(value);
            return key;
        }

        String getStringKey(java.lang.Long value) {
            StringBuffer sb = new StringBuffer();
            sb.append(value);
            return sb.toString();
        }

        public String getAsString(FacesContext facesContext, UIComponent component, Object object) {
            if (object == null) {
                return null;
            }
            if (object instanceof BillingRequestEntity) {
                BillingRequestEntity o = (BillingRequestEntity) object;
                return getStringKey(o.getId());
            } else {
                throw new IllegalArgumentException("object " + object + " is of type " + object.getClass().getName() + "; expected type: " + BillingRequestEntityController.class.getName());
            }
        }
    }

    public List<BillingRequestEntity> getAllCIABillingRequests() {
        allCIABillingRequests = ejbFacade.findAllCIARequests();
        return allCIABillingRequests;
    }

    public void setAllCIABillingRequests(List<BillingRequestEntity> allCIABillingRequests) {
        this.allCIABillingRequests = allCIABillingRequests;
    }

    public List<BillingRequestEntity> getAllNormalBillingRequests() {
        allNormalBillingRequests = ejbFacade.findAllNormalRequests();
        return allNormalBillingRequests;
    }

    public void setAllNormalBillingRequests(List<BillingRequestEntity> allNormalBillingRequests) {
        this.allNormalBillingRequests = allNormalBillingRequests;
    }

    public BillingRequestEntity getCurrent() {
        return current;
    }

    public void setCurrent(BillingRequestEntity current) {
        this.current = current;
    }

    public CustomerInvoiceEntityController getCustomerInvoiceEntityController() {
        return customerInvoiceEntityController;
    }

    public void setCustomerInvoiceEntityController(CustomerInvoiceEntityController customerInvoiceEntityController) {
        this.customerInvoiceEntityController = customerInvoiceEntityController;
    }
    
    public void calculateDueAmount(CustomerInvoiceEntity invoice){
        double amountDue = invoice.getBillingRequest().getRequestedAmount();
        SalesOrderEntity salesOrder = invoice.getBillingRequest().getSalesOrder();
        if(invoice.getType()==InvoiceType.normal && salesOrder.getCashPayableAccountedFor()==null){
            amountDue -= invoice.getBillingRequest().getSalesOrder().getCashPayable();
            salesOrder.setCashPayableAccountedFor(current);
            salesOrder.modified(getLoginPerson());
            salesOrderFacade.edit(salesOrder);
        }
         
        invoice.setAmount(amountDue);
    }

    //CIA or normal
    public void generateInvoice() {
        try {
            System.out.print("Generating invoice...");
            if(current.hasInvoice())
                return;
            
            CustomerInvoiceEntity invoice = new CustomerInvoiceEntity();
            invoice.setBillingRequest(current);
            invoice.setType(current.getType());
            invoice.setStatus(InvoiceStatus.draft);

            invoice.setCustomerAccount(current.getSalesOrder().getCustomer().getCustomerAccount());
            calculateDueAmount(invoice);
            if (invoice.discountPenaltyApply()) //CIA does not need those
            {
                invoice.calculatedDueDatesPenaltyAndDiscount();
            }

            invoice.created(getLoginPerson());
            customerInvoiceFacade.create(invoice);

            customerInvoiceEntityController.setCurrent(invoice);

            current.setInvoice(invoice);
            update();

            HttpServletRequest request = (HttpServletRequest) super.getFacesContext().getExternalContext().getRequest();
            String path = PDFGenerator.generatePDFFromUrl(request, "ViewInvoiceNoFrame.xhtml", invoice.getId(), null);
            pdfDownloadController.setPath(path);

            //do not schedule timer for cash in advance invoices
            if (invoice.getType() == InvoiceType.cashInAdvance) {
                return;
            }
//            customerInvoiceFacade.scheduleTimer(invoice.getDueDate(), invoice.getId());
            //for test only
            Calendar cal = Calendar.getInstance();
            cal.add(Calendar.MINUTE, 3);
            customerInvoiceFacade.scheduleTimer(cal.getTime(), invoice.getId());

        } catch (CustomerAccountDoesNotExistException ex) {
            JsfUtil.addErrorMessage(ex, ex.getMessage());
        }
    }

    public DownloadPDF getPdfDownloadController() {
        return pdfDownloadController;
    }

    public void setPdfDownloadController(DownloadPDF pdfDownloadController) {
        this.pdfDownloadController = pdfDownloadController;
    }

    public List<BillingRequestEntity> getAllBillingRequestsForSalesOrder() {
        allBillingRequestsForSalesOrder = (List<BillingRequestEntity>)salesOrderEntityController.getSelected().getBillingRequests();
        return allBillingRequestsForSalesOrder;
    }

    public void setAllBillingRequestsForSalesOrder(List<BillingRequestEntity> allBillingRequestsForSalesOrder) {
        this.allBillingRequestsForSalesOrder = allBillingRequestsForSalesOrder;
    }

    public SalesOrderEntityController getSalesOrderEntityController() {
        return salesOrderEntityController;
    }

    public void setSalesOrderEntityController(SalesOrderEntityController salesOrderEntityController) {
        this.salesOrderEntityController = salesOrderEntityController;
    }
    
}
